﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.International.Converters.PinYinConverter;
using System.Xml;
using System.Data;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Security.Cryptography;
using Newtonsoft.Json;
using System.Xml.Serialization;

namespace Utilities
{
    /// <summary>
    /// 此类作为扩展方法
    /// </summary>
    public static class ExtensionMethod
    {
        //扩展日期类型
        private static Regex regex = new Regex(@"(?<num>\d+)/*(?<name>[年|月|日])");

        /// <summary>
        /// 添加时间 如 1/年、1年、1月、1/月
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static DateTime Add(this DateTime obj, string format)
        {
            int num = 0, oldDay = obj.Day, curDay = 0;

            if (!string.IsNullOrEmpty(format))
            {
                foreach (Match match in regex.Matches(format))
                {
                    num = int.Parse(match.Groups["num"].Value);

                    switch (match.Groups["name"].Value)
                    {
                        case "年":
                            obj = obj.AddYears(num);
                            break;
                        case "月":
                            obj = obj.AddMonths(num);
                            break;
                        case "日":
                            obj = obj.AddDays(num);
                            break;
                    }
                }
            }
            curDay = obj.Day;
            if (oldDay == curDay)
            {
                obj = obj.AddDays(-1);

            }
            return obj;
        }


        public static string[] MatchValues(this string input, string pattern)
        {
            if (string.IsNullOrEmpty(input))
                return new string[0];

            return (from Match m in Regex.Matches(input, pattern) select m.Value).ToArray();
        }

        public static string[] SplitEmpty(this string input)
        {
            return MatchValues(input, "[^\\s]+");
        }


        public static string ToJson(this 
            object obj)
        {
            return Web.JSONHelp.Serialize(obj);
        }


        /// <summary>
        /// Ext.Net的
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="record"></param>
        /// <returns></returns>
        public static T ToObject<T>(this XmlNode record)
        {
            string json = JsonConvert.SerializeXmlNode(record);
            json = json.Substring(10, json.Length - 11);

            JsonSerializer serializer = new JsonSerializer();
            serializer.MissingMemberHandling = MissingMemberHandling.Ignore;
            StringReader sr = new StringReader(json);
            T obj = (T)serializer.Deserialize(sr, typeof(T));

            return obj;
        }


        public static string QUOTENAME(this string input)
        {
            return string.Format("QUOTENAME('{0}','''')", input);
        }

        public static string QUOTENAME(this string input, string quote)
        {
            return string.Format("QUOTENAME('{0}','{1}')", input, quote);
        }

        public static string Cut(this string input, int len)
        {
            return StringUtil.CutStringByte(input, len, "...");
        }


        public static string GetPinYin(this string chinese)
        {
            Char[] chineseChars = chinese.ToCharArray();

            return string.Join("", chineseChars.GetPinyins(0));
        }


        public static IEnumerable<string> GetPinYins(this string chinese)
        {
            Char[] chineseChars = chinese.ToCharArray();

            return chineseChars.GetPinyins(0);
        }

        public static IEnumerable<string> PinyinsWithoutSound(this ChineseChar chineseChar)
        {
            return chineseChar.Pinyins.Where(p => p != null).Select(p => p.Substring(0, p.Length - 1)).Distinct();
        }

        private static IEnumerable<string> GetPinyins(this char[] chinese, int startIndex)
        {
            //If the start index is beyond the string length, just yield return an empty string.
            if (startIndex == chinese.Length)
            {
                yield return string.Empty;
            }
            else
            {
                //If this char is a chinese char.
                if (ChineseChar.IsValidChar(chinese[startIndex]))
                {
                    foreach (var charPinyin in (new ChineseChar(chinese[startIndex])).PinyinsWithoutSound())
                    {
                        foreach (var remainingPinyins in chinese.GetPinyins(startIndex + 1))
                        {
                            yield return charPinyin + remainingPinyins;
                        }
                    }
                }
                else
                {
                    //Is not chinese, just concat it with the remaining pinyins.
                    foreach (var remainingPinyins in chinese.GetPinyins(startIndex + 1))
                    {
                        yield return chinese[startIndex] + remainingPinyins;
                    }
                }
            }
        }





        #region 连接字符串(扩展)
        /// <summary>
        /// 连接字符串(扩展方法)
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">扩展对象</param>
        /// <param name="separator">分隔符号</param>
        /// <param name="isRemoveEmptyOrNull">是否移除Empty或者Null</param>
        /// <returns>连接后的字符串</returns>
        public static string ConcatSymbol<T>(this IEnumerable<T> list, string separator, bool isRemoveEmptyOrNull)
        {
            return StringUtil.Join(separator, "", "", list, isRemoveEmptyOrNull);
        }


        /// <summary>
        /// 连接字符串
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">扩展对象</param>
        /// <param name="separator">分隔符号</param>
        /// <returns>连接后的字符串</returns>
        public static string ConcatSymbol<T>(this IEnumerable<T> list, string separator)
        {
            return StringUtil.Join(separator, list, false);
        }

        /// <summary>
        /// 连接字符串
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">扩展对象</param>
        /// <param name="separator">分隔符号</param>
        /// <param name="leftSymbol">左边的符号</param>
        /// <param name="rightSymbol">右边的符号</param>
        /// <param name="isRemoveEmptyOrNull">是否移除空</param>
        /// <returns>连接后的字符串</returns>
        public static string ConcatSymbol<T>(this IEnumerable<T> list, string separator, string leftSymbol, string rightSymbol, bool isRemoveEmptyOrNull)
        {
            return StringUtil.Join(separator, leftSymbol, rightSymbol, list, isRemoveEmptyOrNull);
        }





        public static string SqlIn<T>(this IEnumerable<T> list)
        {
            return StringUtil.Join(",", "'", "'", list, false, false);
        }

        public static string SqlIn<T>(this IEnumerable<T> list, bool isInt)
        {
            return StringUtil.Join(",", "", "", list, true, false);
        }



        #endregion

        #region 过滤sql 中的 字符
        /// <summary>
        /// 过滤sql中的 字符
        /// </summary>
        /// <param name="parmText"></param>
        /// <returns></returns>
        public static string SqlFilter(this string source)
        {
            return StringUtil.SqlFilter(source);
        }

        public static string TrimSqlFilter(this object obj)
        {
            if (obj == null)
                return "";
            return StringUtil.SqlFilter(obj.ToString().Trim());
        }
        #endregion

        /// <summary>
        /// 恢复sql的字符
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string SqlRegress(this string source)
        {
            if (source == null)
                return "";
            return StringUtil.SqlRegress(source);
        }


        #region 连接字符串并且过滤sql特殊字符
        /// <summary>
        /// 连接字符串并且过滤sql特殊字符
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">扩展对象</param>
        /// <param name="separator">分隔符号</param>
        /// <returns>连接后的字符串</returns>
        public static string ConcatSqlFilter<T>(this IEnumerable<T> list, string separator)
        {
            return StringUtil.Join(separator, "", "", list, false, true);
        }

        /// <summary>
        /// 连接字符串并且过滤sql特殊字符
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">扩展对象</param>
        /// <param name="separator">分隔符号</param>
        /// <param name="isRemoveEmptyOrNull">是否移除空或空字符串</param>
        /// <returns>连接后的字符串</returns>
        public static string ConcatSqlFilter<T>(this IEnumerable<T> list, string separator, bool isRemoveEmptyOrNull)
        {
            return StringUtil.Join(separator, "", "", list, false, isRemoveEmptyOrNull);
        }



        /// <summary>
        /// 连接字符串并且过滤sql特殊字符
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">扩展对象</param>
        /// <param name="separator">分隔符号</param>
        /// <param name="leftSymbol">左边的符号</param>
        /// <param name="rightSymbol">右边的符号</param>
        /// <param name="isRemoveEmptyOrNull">是否移除空</param>
        /// <returns>连接后的字符串</returns>
        public static string ConcatSqlFilter<T>(this IEnumerable<T> list, string separator, string leftSymbol, string rightSymbol, bool isRemoveEmptyOrNull)
        {
            return StringUtil.Join(separator, leftSymbol, rightSymbol, list, isRemoveEmptyOrNull, true);
        }
        #endregion




        /// <summary>
        /// 直接对对象进行字符串除空
        /// </summary>
        /// <param name="obj">任意对象</param>
        /// <returns></returns>
        public static string NullTrim(this object obj)
        {
            if (obj == null)
                return "";
            return obj.ToString().Trim();
        }



        //转换
        public static DateTime? ToDate(this string input)
        {
            DateTime t;
            if (DateTime.TryParse(input, out t))
                return t;

            return default(DateTime?);
        }

        public static int? ToInt(this string input)
        {
            int t;
            if (int.TryParse(input, out t))
                return t;

            return default(int?);
        }

        public static decimal? ToDecimal(this string input)
        {
            decimal t;
            if (decimal.TryParse(input, out t))
                return t;

            return default(decimal?);
        }

        public static double? ToDouble(this string input)
        {
            double t;
            if (double.TryParse(input, out t))
                return t;

            return default(double?);
        }

        public static Guid? ToGuid(this string input)
        {
            Guid t;
            if (Guid.TryParse(input, out t))
                return t;

            return default(Guid?);
        }


        public static IEnumerable<TSource> Each<TSource>(this IEnumerable<TSource> source, Action<TSource> predicate)
        {
            foreach (TSource s in source)
            {
                predicate(s);
            }
            return source;
        }



        public static string SerializeXml<T>(this T obj)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            StringBuilder sb = new StringBuilder();
            using (XmlWriter writer = XmlWriter.Create(sb))
            {
                serializer.Serialize(writer, obj);
                return sb.ToString();
            }
        }

        public static T DeserializeXml<T>(this string input)
            where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            StringReader strReader = new StringReader(input);
            XmlReader xmlReader = XmlReader.Create(strReader);
            return serializer.Deserialize(xmlReader) as T;
        }





        public static DateTime GetMonday(this DateTime date)
        {

            int day = (date.DayOfWeek == 0 ? 7 : (int)date.DayOfWeek) - 1;
            DateTime monday = date.AddDays(int.Parse("-" + day));
            return monday;

        }






        #region DataTable DataRow DataReader 转换
        public static T ToModel<T>(this DataRow row)
            where T : class, new()
        {
            // return EntityHelper<T>.ConvertEntity(row);
            return NBear.Mapping.ObjectConvertor.ToObject<DataRow, T>(row);
        }

        public static T[] ToArray<T>(this IDataReader reader)
           where T : class, new()
        {
            return NBear.Mapping.ObjectConvertor.ToArray<IDataReader, T>(reader);
        }


        public static T[] ToArray<T>(this DataTable data)
          where T : class, new()
        {
            return NBear.Mapping.ObjectConvertor.ToArray<DataRow, T>(data);
        }

        public static T[] ToArray<T>(this DataRowCollection data)
         where T : class, new()
        {
            return NBear.Mapping.ObjectConvertor.ToArray<DataRow, T>(data);
        }

        public static T[] ToArray<T>(this IEnumerable<DataRow> data)
        where T : class, new()
        {
            return NBear.Mapping.ObjectConvertor.ToArray<DataRow, T>(data);
        }
        #endregion

        #region ConvertToObject
        public static R ConvertToObject<S, R>(this S source)
            where R : class, new()  
            where S : class, new()
        {

            if (source == null)
                return (R)null;
            Type rType = typeof(R);
            Type sType = typeof(S);
            //.Where()

            PropertyInfo[] rInfos = rType.GetProperties();
            PropertyInfo[] sInfos = sType.GetProperties();

            PropertyInfo temp = null;
            R instance = new R();
            foreach (var p in rInfos)
            {
                if (p.PropertyType == typeof(string) || p.PropertyType.IsValueType)
                {
                    temp = sInfos.FirstOrDefault(pinfo => pinfo.Name == p.Name);
                    if (temp != null)
                        p.SetValue(instance, temp.GetValue(source, null), null);
                }
            }

            return instance;
        }
        #endregion

        /// <summary>
        /// 扩展属性复制
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T PropertiesClone<T>(this object source) where T : class, new()
        {
            T t = new T();

            foreach (PropertyInfo p in EntityHelper<T>.GetPropertyInfos(t.GetType()))
            {
                if (p.CanWrite)
                    p.SetValue(t, p.GetValue(source, null), null);
            }
            return t;
        }


        /// <summary>
        /// 属性为String类型 trim并且null变为""
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static void PropertiesNullTrim(this object source)
        {
            if (source == null) return;

            Type type = source.GetType();
            string val = null;
            foreach (PropertyInfo p in type.GetProperties())
            {
                if (p.PropertyType != typeof(string))
                    continue;

                if (p.CanWrite)
                {
                    val = ((string)p.GetValue(source, null)).NullTrim();
                    p.SetValue(source, val, null);
                }
            }
        }



        #region PropertiesCopyTo

        /// <summary>
        /// 把来源的属性拷贝到目标上
        /// 浅复制
        /// </summary>
        /// <typeparam name="S">来源类型</typeparam>
        /// <typeparam name="R">目标类型</typeparam>
        /// <param name="source">来源对象</param>
        /// <param name="target">目标对象</param>
        /// <param name="filterNull">是否过滤NULL</param>
        public static void PropertiesCopyTo<S, R>(this S source, R target)
            where R : class, new()
            where S : class, new()
        {

            PropertiesCopyTo(source, target, false);
        }


        /// <summary>
        /// 把来源的属性拷贝到目标上
        /// 浅复制
        /// </summary>
        /// <typeparam name="S">来源类型</typeparam>
        /// <typeparam name="R">目标类型</typeparam>
        /// <param name="source">来源对象</param>
        /// <param name="target">目标对象</param>
        /// <param name="filterNull">是否过滤NULL</param>
        public static void PropertiesCopyTo<S, R>(this S source, R target, bool filterNull)
        {
            if (source == null)
            {
                target = default(R);
                return;
            }

            Type rType = typeof(R);
            Type sType = typeof(S);


            PropertyInfo[] rInfos = rType.GetProperties();
            PropertyInfo[] sInfos = sType.GetProperties();

            PropertyInfo temp = null;

            object value = null;
            foreach (var p in rInfos)
            {
                if (!p.CanWrite)
                    continue;
                //基础类型操作
                if (p.PropertyType == typeof(string) || p.PropertyType.IsValueType)
                {
                    temp = sInfos.FirstOrDefault(pinfo => pinfo.Name == p.Name);
                    if (temp != null)
                    {
                        value = temp.GetValue(source, null);
                        //可能要类型转换 暂时不写

                        if (value == null && filterNull)
                            continue;

                        p.SetValue(target, value, new object[0]);

                    }
                }
            }

        }
        #endregion

        #region ConvertToObjectList
        public static List<R> ConvertToObjectList<S, R>(this IEnumerable source)
            where R : class, new()
            where S : class, new()
        {
            if (source == null)
                return (List<R>)null;
            Type rType = typeof(R);
            Type sType = typeof(S);

            PropertyInfo[] rInfos = rType.GetProperties();
            PropertyInfo[] sInfos = sType.GetProperties();

            PropertyInfo temp = null;
            List<R> list = new List<R>();
            S obj = null;
            foreach (var item in source)
            {
                if (item == null)
                {
                    list.Add((R)null);
                    continue;
                }
                obj = (S)item;
                R instance = new R();
                foreach (var p in rInfos)
                {
                    if (p.PropertyType == typeof(string) || p.PropertyType.IsValueType)
                    {
                        temp = sInfos.FirstOrDefault(pinfo => pinfo.Name == p.Name);
                        if (temp != null)
                            p.SetValue(instance, temp.GetValue(obj, null), null);
                    }
                }
                list.Add(instance);
            }

            return list;
        }
        #endregion

        #region 计算HASH码操作
        public static string ComputeHash(this byte[] data)
        {

            using (HashAlgorithm hashAlg = HashAlgorithm.Create())
            {
                return BitConverter.ToString(hashAlg.ComputeHash(data));
            }
        }

        public static string ComputeHash(this Stream stream)
        {
            using (HashAlgorithm hashAlg = HashAlgorithm.Create())
            {
                return BitConverter.ToString(hashAlg.ComputeHash(stream));
            }
        }
        #endregion
    }
}
